package com.linkhub.oms.admin.modules.user.accountrecharge.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.linkhub.oms.admin.common.enums.BankStatementEnum;
import com.linkhub.oms.admin.common.exception.ExceptionFactory;
import com.linkhub.oms.admin.modules.user.account.domain.dto.UserAccountDTO;
import com.linkhub.oms.admin.modules.user.account.service.IUserAccountService;
import com.linkhub.oms.admin.modules.user.accountflow.domain.dto.UserAccountFlowDTO;
import com.linkhub.oms.admin.modules.user.accountflow.service.IUserAccountFlowBizService;
import com.linkhub.oms.admin.modules.user.accountrecharge.domain.param.*;
import com.linkhub.oms.admin.modules.user.accountrecharge.domain.vo.UserRechargeRecordDetailVO;
import com.linkhub.oms.admin.modules.user.accountrecharge.domain.vo.UserRechargeRecordMatchVO;
import com.linkhub.oms.admin.modules.user.accountrecharge.domain.vo.UserRechargeRecordVO;
import com.linkhub.oms.admin.modules.user.accountrecharge.service.IUserRechargeRecordService;
import com.linkhub.oms.admin.modules.user.attachment.domain.vo.UserAttachmentVO;
import com.linkhub.oms.admin.modules.user.attachment.service.IUserAttachmentService;
import com.linkhub.oms.admin.modules.user.domain.param.BaseUserParam;
import com.linkhub.oms.admin.modules.user.domain.vo.MerchantBankCardVO;
import com.linkhub.oms.common.enums.mp.*;
import com.linkhub.oms.common.response.PageDTO;
import com.linkhub.oms.common.util.QtBeanUtil;
import com.linkhub.oms.common.util.QtBigDecimalUtil;
import com.linkhub.oms.common.util.QtStreamUtil;
import com.linkhub.oms.dao.mapper.UserRechargeRecordEntityMapper;
import com.linkhub.oms.dao.mpservice.IBankCardService;
import com.linkhub.oms.dao.mpservice.IUserService;
import com.linkhub.oms.entity.BankCardEntity;
import com.linkhub.oms.entity.UserAttachmentEntity;
import com.linkhub.oms.entity.UserEntity;
import com.linkhub.oms.entity.UserRechargeRecordEntity;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * <p>
 * 用户充值记录表 服务实现类
 * </p>
 *
 * @author Frank
 * @since 2024-05-26
 */
@Service
public class UserRechargeRecordServiceImpl extends ServiceImpl<UserRechargeRecordEntityMapper, UserRechargeRecordEntity> implements IUserRechargeRecordService {
    @Resource
    private UserRechargeRecordEntityMapper userRechargeRecordEntityMapper;
    @Resource
    private IUserService userService;
    @Resource
    private IUserAttachmentService userAttachmentService;
    @Resource
    private IUserAccountService accountService;
    @Resource
    private IUserAccountFlowBizService accountFlowService;
    @Resource
    private IBankCardService bankCardService;


    @Override
    public PageDTO<UserRechargeRecordVO> getRechargeRecordPage(UserAccountRechargeQueryParam param) {
        LambdaQueryWrapper<UserRechargeRecordEntity> queryWrapper = Wrappers.lambdaQuery(UserRechargeRecordEntity.class)
                .eq(Objects.nonNull(param.getRechargeStatus()), UserRechargeRecordEntity::getRechargeStatus, param.getRechargeStatus())
                .eq(param.isCustomRoleFlag(), UserRechargeRecordEntity::getUserId, param.getUserId())
                .in(CollUtil.isNotEmpty(param.getMerchantUserIds()), UserRechargeRecordEntity::getUserId, param.getMerchantUserIds())
                .eq(UserRechargeRecordEntity::getDataStatus, DataStatusEnum.ENABLE)
                .orderByDesc(UserRechargeRecordEntity::getSubmitDate);
        appendQueryDate(queryWrapper, param);

        Page<UserRechargeRecordEntity> objectPage = new Page<>(param.getPage(), param.getSize());
        Page<UserRechargeRecordEntity> page = super.page(objectPage, queryWrapper);

        PageDTO<UserRechargeRecordVO> userRechargeRecordPage = userRechargeRecordBuilder(page);
        setUserName(userRechargeRecordPage, param.isCustomRoleFlag());
        return userRechargeRecordPage;
    }

    @Override
    public UserRechargeRecordDetailVO getRechargeRecordDetail(String transactionId) {
        LambdaQueryWrapper<UserRechargeRecordEntity> queryWrapper = Wrappers.lambdaQuery(UserRechargeRecordEntity.class)
                .eq(UserRechargeRecordEntity::getTransactionId, transactionId)
                .eq(UserRechargeRecordEntity::getDataStatus, DataStatusEnum.ENABLE);
        UserRechargeRecordEntity userRechargeRecordEntity = userRechargeRecordEntityMapper.selectOne(queryWrapper);
        if (Objects.isNull(userRechargeRecordEntity)) {
            return new UserRechargeRecordDetailVO();
        }
        String userId = userRechargeRecordEntity.getUserId();
        UserEntity userEntity = userService.getUserByUserId(userId);
        List<UserAttachmentEntity> userAttachments = userAttachmentService.getByUserId(userId,
                userRechargeRecordEntity.getId(),
                UserAttachmentEnum.USER_RECHARGE);
        return buildRechargeDetail(userRechargeRecordEntity, userEntity, userAttachments);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitRecharge(UserRechargeRecordAddParam userRechargeRecordAddParam) {
        String merchantUserId = userRechargeRecordAddParam.getMerchantUserId();
        UserRechargeRecordEntity userRechargeRecordEntity = new UserRechargeRecordEntity();
        QtBeanUtil.copyProperties(userRechargeRecordAddParam, userRechargeRecordEntity);
        userRechargeRecordEntity.setUserId(merchantUserId);
        userRechargeRecordEntity.setTransactionId(IdUtil.getSnowflake().nextIdStr());
        userRechargeRecordEntity.setSubmitDate(LocalDate.now());
        userRechargeRecordEntity.setTransferAmount(QtBigDecimalUtil.valueOf(userRechargeRecordAddParam.getTransferAmount()));
        userRechargeRecordEntity.setTransferExchangeRate((QtBigDecimalUtil.valueOf(userRechargeRecordAddParam.getTransferExchangeRate())));
        userRechargeRecordEntity.setUpdateUserId(userRechargeRecordAddParam.getUserId());
        userRechargeRecordEntity.setCreatedUserId(userRechargeRecordAddParam.getUserId());
        this.save(userRechargeRecordEntity);
        //保存附件
        userAttachmentService.saveAttachmentBatch(merchantUserId,
                userRechargeRecordEntity.getId(),
                UserAttachmentEnum.USER_RECHARGE,
                userRechargeRecordAddParam.getAttachmentList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void auditRechargeSuc(UserRechargeRecordUpdParam userRechargeRecordUpdParam) {
        UserRechargeRecordEntity userRechargeRecordEntity = this.getById(userRechargeRecordUpdParam.getId());
        checkRecharge(userRechargeRecordEntity);
        BigDecimal transferAmount = userRechargeRecordEntity.getTransferAmount();
        BigDecimal receivedAmount = QtBigDecimalUtil.valueOf(userRechargeRecordUpdParam.getReceivedAmount());
        if (QtBigDecimalUtil.lt(transferAmount, receivedAmount)) {
            throw ExceptionFactory.getI18nBizException("user.recharge.amount.error");
        }
        UserRechargeRecordEntity userRechargeRecordEntityUpd = new UserRechargeRecordEntity();
        userRechargeRecordEntityUpd.setId(userRechargeRecordUpdParam.getId());
        userRechargeRecordEntityUpd.setReceivedAmount(receivedAmount);
        userRechargeRecordEntityUpd.setReceivedExchangeRate(QtBigDecimalUtil.valueOf(userRechargeRecordUpdParam.getReceivedExchangeRate()));
        userRechargeRecordEntityUpd.setReceivedDate(userRechargeRecordUpdParam.getReceivedDate());
        userRechargeRecordEntityUpd.setReceivedBankName(userRechargeRecordUpdParam.getReceivedBankName());
        userRechargeRecordEntityUpd.setReceivedCardNumber(userRechargeRecordUpdParam.getReceivedCardNumber());
        userRechargeRecordEntityUpd.setReceivedBankStatement(userRechargeRecordUpdParam.getReceivedBankStatement());
        userRechargeRecordEntityUpd.setFeeCurrencyType(userRechargeRecordUpdParam.getFeeCurrencyType());
        userRechargeRecordEntityUpd.setFee(QtBigDecimalUtil.valueOf(userRechargeRecordUpdParam.getFee()));
        userRechargeRecordEntityUpd.setActualRechargeAmount(QtBigDecimalUtil.valueOf(userRechargeRecordUpdParam.getActualRechargeAmount()));
        userRechargeRecordEntityUpd.setRechargeStatus(RechargeStatusEnum.RECEIVED);
        userRechargeRecordEntityUpd.setUpdateUserId(userRechargeRecordUpdParam.getUserId());
        this.updateById(userRechargeRecordEntityUpd);

        //充值到账户
        BigDecimal actualRechargeAmount = userRechargeRecordEntityUpd.getActualRechargeAmount();
        UserAccountDTO userAccountDTO = accountService.updateAccountAmount(userRechargeRecordEntity.getUserId(),
                actualRechargeAmount,
                TransactionTypeEnum.INCOME);

        //生成充值资金流水
        UserAccountFlowDTO userAccountFlowDTO = new UserAccountFlowDTO();
        userAccountFlowDTO.setUserId(userRechargeRecordEntity.getUserId());
        userAccountFlowDTO.setTransactionId(userRechargeRecordEntity.getTransactionId());
        userAccountFlowDTO.setTransactionType(TransactionTypeEnum.INCOME);
        userAccountFlowDTO.setDocumentId(userRechargeRecordEntity.getTransactionId());
        userAccountFlowDTO.setDocumentType(DocumentTypeEnum.RECHARGE_ORDER);
        userAccountFlowDTO.setExpenseType(ExpenseTypeEnum.RECHARGE);
        userAccountFlowDTO.setAmount(actualRechargeAmount);
        userAccountFlowDTO.setRemainingBalance(userAccountDTO.getTotalBalance());
        accountFlowService.saveAccountFlow(userAccountFlowDTO);
    }


    @Override
    public void auditRechargeFail(UserRechargeRecordRefuseParam userRechargeRecordRefuseParam) {
        UserRechargeRecordEntity userRechargeRecordEntity = this.getById(userRechargeRecordRefuseParam.getId());
        checkRecharge(userRechargeRecordEntity);
        UserRechargeRecordEntity userRechargeRecordEntityUpd = new UserRechargeRecordEntity();
        userRechargeRecordEntityUpd.setId(userRechargeRecordRefuseParam.getId());
        userRechargeRecordEntityUpd.setRefuseReason(userRechargeRecordRefuseParam.getReason());
        userRechargeRecordEntityUpd.setRechargeStatus(RechargeStatusEnum.REFUSED);
        userRechargeRecordEntityUpd.setUpdateUserId(userRechargeRecordRefuseParam.getUserId());
        this.updateById(userRechargeRecordEntityUpd);
    }

    @Override
    public boolean checkBankStatement(UserRechargeRecordCheckParam userRechargeRecordCheckParam) {
        if (StringUtils.isBlank(userRechargeRecordCheckParam.getBankStatement())) {
            return true;
        }
        //校验转账银行流水
        LambdaQueryWrapper<UserRechargeRecordEntity> lambdaWrapper = Wrappers.lambdaQuery(UserRechargeRecordEntity.class);
        if (Objects.equals(BankStatementEnum.TRANSFER.getCode(), userRechargeRecordCheckParam.getType())) {
            lambdaWrapper.eq(UserRechargeRecordEntity::getTransferBankStatement, userRechargeRecordCheckParam.getBankStatement())
                    .in(UserRechargeRecordEntity::getRechargeStatus, Lists.newArrayList(RechargeStatusEnum.IN_REVIEW, RechargeStatusEnum.RECEIVED))
                    .eq(UserRechargeRecordEntity::getDataStatus, DataStatusEnum.ENABLE);
            return userRechargeRecordEntityMapper.selectCount(lambdaWrapper) == 0;
        }
        //校验到账银行流水
        lambdaWrapper.eq(UserRechargeRecordEntity::getReceivedBankStatement, userRechargeRecordCheckParam.getBankStatement())
                .eq(UserRechargeRecordEntity::getRechargeStatus, RechargeStatusEnum.RECEIVED)
                .eq(UserRechargeRecordEntity::getDataStatus, DataStatusEnum.ENABLE);
        return userRechargeRecordEntityMapper.selectCount(lambdaWrapper) == 0;
    }

    @Override
    public List<MerchantBankCardVO> getPayBankCard(String merchantUserId, BaseUserParam baseUserParam) {
        List<MerchantBankCardVO> bankCardVOList = Lists.newArrayList();
        String userIdQuery;
        if (baseUserParam.isCustomRoleFlag()) {
            userIdQuery = baseUserParam.getUserId();
        } else {
            userIdQuery = merchantUserId;
        }
        if (StringUtils.isBlank(userIdQuery)) {
            return bankCardVOList;
        }
        List<BankCardEntity> bankCardList = bankCardService.listByUserId(userIdQuery);
        if (CollUtil.isEmpty(bankCardList)) {
            return bankCardVOList;
        }
        return QtBeanUtil.copyList(bankCardList, MerchantBankCardVO::new);
    }

    @Override
    public List<UserRechargeRecordMatchVO> listByReceivedBankStatement(List<String> receivedBankStatements) {
        if (CollUtil.isEmpty(receivedBankStatements)) {
            return Lists.newArrayList();
        }
        List<UserRechargeRecordEntity> rechargeRecordList = lambdaQuery()
                .select(UserRechargeRecordEntity::getId,
                        UserRechargeRecordEntity::getTransactionId,
                        UserRechargeRecordEntity::getPayCardNumber,
                        UserRechargeRecordEntity::getReceivedBankStatement)
                .in(UserRechargeRecordEntity::getReceivedBankStatement, receivedBankStatements)
                .eq(UserRechargeRecordEntity::getRechargeStatus, RechargeStatusEnum.RECEIVED)
                .eq(UserRechargeRecordEntity::getDataStatus, DataStatusEnum.ENABLE)
                .list();
        return QtStreamUtil.map(rechargeRecordList, UserRechargeRecordMatchVO::new);
    }

    /**
     * 校验充值记录
     */
    private void checkRecharge(UserRechargeRecordEntity userRechargeRecordEntity) {
        if (Objects.isNull(userRechargeRecordEntity)) {
            throw ExceptionFactory.getI18nBizException("user.recharge.record.does.not.exist");
        }
        if (!Objects.equals(RechargeStatusEnum.IN_REVIEW, userRechargeRecordEntity.getRechargeStatus())) {
            throw ExceptionFactory.getI18nBizException("user.recharge.record.has.audited");
        }
    }

    /**
     * 设置商户名称
     */
    private void setUserName(PageDTO<UserRechargeRecordVO> userRechargeRecordPage, boolean customRoleFlag) {
        List<UserRechargeRecordVO> records = userRechargeRecordPage.getRecords();
        if (!customRoleFlag && CollUtil.isNotEmpty(records)) {
            List<String> userIds = QtStreamUtil.mapAndDistinct(records, UserRechargeRecordVO::getMerchantUserId);
            List<UserEntity> userEntities = userService.listByUserId(userIds);
            Map<String, UserEntity> userIdUserMap = QtStreamUtil.toMap(userEntities, UserEntity::getUserId);
            records.forEach(record -> {
                UserEntity userEntity = userIdUserMap.get(record.getMerchantUserId());
                if (Objects.nonNull(userEntity)) {
                    record.setMerchantUserName(userEntity.getUserName());
                }
            });
        }
    }

    /**
     * 设置查询时间
     */
    private void appendQueryDate(LambdaQueryWrapper<UserRechargeRecordEntity> queryWrapper, UserAccountRechargeQueryParam param) {
        LocalDate dateBegin;
        LocalDate dateEnd;
        if (StringUtils.isBlank(param.getSubmitDateBegin()) || StringUtils.isBlank(param.getSubmitDateEnd())) {
            //默认查询3个月
            dateBegin = LocalDate.now().minusDays(90);
            dateEnd = LocalDate.now();
        } else {
            dateBegin = LocalDate.parse(param.getSubmitDateBegin());
            dateEnd = LocalDate.parse(param.getSubmitDateEnd());
        }
        queryWrapper.le(UserRechargeRecordEntity::getSubmitDate, dateEnd)
                .ge(UserRechargeRecordEntity::getSubmitDate, dateBegin);
    }

    /**
     * 构建PageDTO<UserRechargeRecordVO>
     */
    private PageDTO<UserRechargeRecordVO> userRechargeRecordBuilder(Page<UserRechargeRecordEntity> page) {
        PageDTO<UserRechargeRecordVO> res = new PageDTO<>();
        res.setTotal(page.getTotal());
        res.setSize(page.getSize());
        res.setCurrent(page.getCurrent());
        res.setPages(page.getPages());
        List<UserRechargeRecordVO> userRecharges = QtStreamUtil.map(page.getRecords(), UserRechargeRecordVO::new);
        res.setRecords(userRecharges);
        return res;
    }


    /**
     * 构建充值详情
     *
     * @param userRechargeRecordEntity 充值记录
     * @param user                     用户
     * @param userAttachments          附件
     * @return UserRechargeRecordDetailVO
     */
    private UserRechargeRecordDetailVO buildRechargeDetail(UserRechargeRecordEntity userRechargeRecordEntity,
                                                           UserEntity user,
                                                           List<UserAttachmentEntity> userAttachments) {
        UserRechargeRecordDetailVO userRechargeRecordDetailVO = new UserRechargeRecordDetailVO();
        if (Objects.isNull(userRechargeRecordEntity)) {
            return userRechargeRecordDetailVO;
        }
        QtBeanUtil.copyProperties(userRechargeRecordEntity, userRechargeRecordDetailVO);
        if (Objects.nonNull(user)) {
            userRechargeRecordDetailVO.setMerchantUserName(user.getUserName());
            userRechargeRecordDetailVO.setMerchantUserEmail(user.getEmail());
        }
        userRechargeRecordDetailVO.setMerchantUserId(userRechargeRecordEntity.getUserId());
        userRechargeRecordDetailVO.setTransferAmount(QtBigDecimalUtil.toString(userRechargeRecordEntity.getTransferAmount()));
        userRechargeRecordDetailVO.setTransferExchangeRate(QtBigDecimalUtil.toString(userRechargeRecordEntity.getTransferExchangeRate()));
        userRechargeRecordDetailVO.setReceivedAmount(QtBigDecimalUtil.toString(userRechargeRecordEntity.getReceivedAmount()));
        userRechargeRecordDetailVO.setReceivedExchangeRate(QtBigDecimalUtil.toString(userRechargeRecordEntity.getReceivedExchangeRate()));
        userRechargeRecordDetailVO.setFee(QtBigDecimalUtil.toString(userRechargeRecordEntity.getFee()));
        userRechargeRecordDetailVO.setActualRechargeAmount(QtBigDecimalUtil.toString(userRechargeRecordEntity.getActualRechargeAmount()));
        userRechargeRecordDetailVO.setRechargeStatus(userRechargeRecordEntity.getRechargeStatus().getCode());
        List<UserAttachmentVO> attachmentList = Lists.newArrayList();
        if (CollUtil.isNotEmpty(userAttachments)) {
            userAttachments.forEach(attachment -> {
                UserAttachmentVO attachmentVO = new UserAttachmentVO();
                attachmentVO.setFileName(attachment.getFileName());
                attachmentVO.setFileUrl(attachment.getFileUrl());
                attachmentList.add(attachmentVO);
            });
        }
        userRechargeRecordDetailVO.setAttachmentList(attachmentList);
        return userRechargeRecordDetailVO;
    }

}
